
var PI_DIV_180 = "0.01745329251994329576923690768489";


function GetDataView(file_name, callback){
    "use strict";
    var xmlhttp;

    if (window.XMLHttpRequest)
    {
        xmlhttp = new XMLHttpRequest();
    } else if (window.ActiveXObject)
    {
        try {
            xmlhttp = new ActiveXObject("MSXML2.XMLHttp.3.0");
        } catch(ex) {
            xmlhttp = null;
        }
    }

    var data_view = [];
    
    if (xmlhttp.overrideMimeType)
    {
            xmlhttp.overrideMimeType("text/plain; charset=x-user-defined");
    }

    xmlhttp.onreadystatechange= function(){
        if (xmlhttp.readyState==200 ||xmlhttp.readyState==4 || xmlhttp.readyState=="complete")
        {
            data_view = new DataView(xmlhttp.response);
            callback(data_view);
        }
    };

    xmlhttp.open("GET", file_name, true);

    xmlhttp.responseType = "arraybuffer";

    xmlhttp.send();

}




function GetLines(file_name){
    "use strict";
    var xmlhttp;

    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
            xmlhttp = new ActiveXObject("MSXML2.XMLHttp.3.0");
        } catch(ex)
        {
            xmlhttp = null;
        }
    }

    var txt;

    xmlhttp.overrideMimeType("text/plain");

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 || xmlhttp.readyState=="complete")
        {
            txt = xmlhttp.responseText;
        }
    };
    xmlhttp.open("GET",file_name,false);
    xmlhttp.send();
    //var lines = txt.split("\r\n");
    var lines = txt.match(/^.*([\n\r]+|$)/gm);

    return lines;
}

function GetText(file_name) {
    "use strict";
    var xmlhttp;

    if (window.XMLHttpRequest)
    {
        xmlhttp = new XMLHttpRequest();
    } else
    if (window.ActiveXObject)
    {
        try {
            xmlhttp = new ActiveXObject("MSXML2.XMLHttp.3.0");
        } catch(ex) {
            xmlhttp = null;
        }
    }
    
    var txt;

    xmlhttp.overrideMimeType("text/plain");
    
    xmlhttp.onreadystatechange= function(){
        if (xmlhttp.readyState==4 || xmlhttp.readyState=="complete"){
            txt = xmlhttp.responseText;
        }
    };
    xmlhttp.open("GET",file_name,false);
    xmlhttp.send();
    
    return txt;
}


var Mesh = (function () {
    "use strict";
    function Mesh(file_name) {

        var data_view,
            positions_,
            normals_,
            tex_coords_,
            indices_,

            triangle_pos_buffer_,
            normal_buffer_,
            tex_coords_buffer_,
            index_buffer_,

            num_pos_,
            num_indices_,
            num_tris_,

            b_ready2draw_ = false;

        /******************************************************/

        this.cont = function (dv) {

            data_view = dv;

            var head = new Uint16Array(2);

            head[0] = data_view.getUint16(0);
            head[1] = data_view.getUint16(2);

            num_pos_ = head[0];
            num_indices_ = head[1];
            num_tris_ = num_indices_ / 3;

            positions_ = new Float32Array(head[0]);

            var i;
            var off;
            for (i = 0, off = 6; i < head[0]; i++, off += 4)
            {
                positions_[i] = data_view.getFloat32(off);
            }

            tex_coords_ = new Float32Array(head[0] * 2 / 3);

            for (i = 0, off = head[0] * 2 * 4 + 6; i < head[0] * 2 / 3; i++, off += 4)
            {
                tex_coords_[i] = data_view.getFloat32(off);
            }

            normals_ = new Float32Array(head[0]);

            for (i = 0, off = head[0] * 4 + 6; i < head[0]; i++, off += 4)
            {
                normals_[i] = data_view.getFloat32(off);
            }

            indices_ = new Uint16Array(head[1]);
            var offset = ((head[0] * 2 + head[0] * 2 / 3 + 1) * 4 + 6);

            for (i = 0, off = offset; i < head[1]; i++, off += 2)
            {
                indices_[i] = data_view.getUint16(off);
            }

            triangle_pos_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
            gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
            triangle_pos_buffer_.itemSize = 3;
            triangle_pos_buffer_.numItems = num_pos_ / 3;

            tex_coords_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);
            gl.bufferData(gl.ARRAY_BUFFER, tex_coords_, gl.STATIC_DRAW);
            tex_coords_buffer_.itemSize = 2;
            tex_coords_buffer_.numItems = num_pos_ / 3;

            normal_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, normal_buffer_);
            gl.bufferData(gl.ARRAY_BUFFER, normals_, gl.STATIC_DRAW);
            tex_coords_buffer_.itemSize = 3;
            tex_coords_buffer_.numItems = num_pos_ / 3;

            index_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices_, gl.STATIC_DRAW);
            index_buffer_.numItems = num_indices_;

            head = null;
            offset = null;

            b_ready2draw_ = true;

        };

        GetDataView(file_name, this.cont);

        //this.cont = null;
        /**********************************************************/

        this.b_ready2draw = function () {
            return b_ready2draw_;
        };

        this.Draw = function () {

            if (!b_ready2draw_)
            {
                return;
            }

            gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);

            gl.enableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);

            if (g_render_state.current_program.hasOwnProperty("aVertexUVs"))
            {
                gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);

                gl.enableVertexAttribArray(g_render_state.current_program.aVertexUVs);
                gl.vertexAttribPointer(g_render_state.current_program.aVertexUVs, 2, gl.FLOAT, true, 0, 0);
            }

            if (g_render_state.current_program.hasOwnProperty("aVertexNormal"))
            {
                gl.bindBuffer(gl.ARRAY_BUFFER, normal_buffer_);

                gl.enableVertexAttribArray(g_render_state.current_program.aVertexNormal);
                gl.vertexAttribPointer(g_render_state.current_program.aVertexNormal, 3, gl.FLOAT, true, 0, 0);
            }

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_);

            gl.drawElements(gl.TRIANGLES, index_buffer_.numItems, gl.UNSIGNED_SHORT, 0);

            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

        };
        
        
        }

    return Mesh;
})();

var Car = (function(){
    "use strict";
    function Car(file_name){
        
        var parts_ = [],
            wheel_indices_ = [],

            stats_ = [],

            lines = GetLines(file_name),
            line = 0,
        
            i;

        var make_local_matrix_func = function() {
            return function(parts){
                if(this.parent_index == -1)
                {
                    return this.local_matrix_;
                } else
                {
                    var temp_matrix = mat4.create();
                    mat4.multiply(parts[this.parent_index].local_matrix(parts), this.local_matrix_, temp_matrix);

                     return temp_matrix;
                }
            };
        };

        while(line < lines.length)
        {
            if(lines[line].indexOf("CarPart") != -1)
            {
                    while(lines[line].indexOf("{") == -1)
                    {
                        line++;
                    }
                    var part = {};
                    part.local_matrix_ = mat4.create();
                    mat4.identity(part.local_matrix_);

                    var name;
                    
                    while(lines[line].indexOf("}") == -1)
                    {
                        if(lines[line].indexOf("name") != -1)
                        {
                            name = lines[line].match(/\w+/g);
                            part.name = name[1];
                        }
                        else
                        if(lines[line].indexOf("mesh") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            if(name[1] != "instanceof")
                            {
    
                                part.mesh = new Mesh(name[1]);

                            }
                            else
                            {
                                for(i = 0; i < parts_.length; i++)
                                {
                                    if(parts_[i].name == name[2])
                                    {
                                        part.mesh = parts_[i].mesh;
                                    }
                                }
                            }
                        }
                        else
                        if(lines[line].indexOf("material") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            part.material_name = name[1];
                        }
                        else
                        if(lines[line].indexOf("diff_texture") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            part.diff_texture = name[1];
                        }
                        else
                        if(lines[line].indexOf("parttype") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            part.parttype = name[1];
                            
                            if(part.parttype == "wheel")
                            {
                                wheel_indices_.push(parts_.length);
                                part.is_wheel = true;
                            }else
                            {
                                part.is_wheel = false;
                            }
                        }
                        else
                        if(lines[line].indexOf("radius") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            part.radius = parseFloat(name[1]);
                            
                        }
                        else
                        if(lines[line].indexOf("snaptoground") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            if(name[1] == "true")
                            {
                                part.snaptoground = true;
                            }
                            else
                            {
                                part.snaptoground = false;
                            }
                            
                        }
                        else
                        if(lines[line].indexOf("offset") != -1)
                        {
                            name = lines[line].match(/[\/.\-\w]+/g);
                            part.offset = new Float32Array(3);
                            part.offset[0] = parseFloat(name[1]);
                            part.offset[1] = parseFloat(name[2]);
                            part.offset[2] = parseFloat(name[3]);
                            
                            //alert();
                            
                            mat4.translate(part.local_matrix_, part.offset);
                        }
                        else
                        if(lines[line].indexOf("rotations") != -1)
                        {
                            name = lines[line].match(/[\/.\-\w]+/g);
                            part.rotations = new Float32Array(3);
                            part.rotations[0] = parseFloat(name[1]) * PI_DIV_180;
                            part.rotations[1] = parseFloat(name[2]) * PI_DIV_180;
                            part.rotations[2] = parseFloat(name[3]) * PI_DIV_180;
                            
                            if(Math.abs(parseFloat(name[2])) > 90)
                            {
                                part.reverse_rotation = true;
                            } else
                            {
                                part.reverse_rotation = false;
                            }
                                
                            mat4.rotateZ(part.local_matrix_, part.rotations[2]);
                            mat4.rotateX(part.local_matrix_, part.rotations[0]);
                            mat4.rotateY(part.local_matrix_, part.rotations[1]);
                        }
                        else
                        if(lines[line].indexOf("parent") != -1)
                        {
                            name = lines[line].match(/[\/.\w]+/g);
                            if(name[1] != "null")
                            {
                                for(i = 0; i < parts_.length; i++)
                                {
                                    if(parts_[i].name == name[1])
                                    {
                                        part.parent_index = i;
                                    }
                                }
                            } else
                            {
                                part.parent_index = -1;
                            }
                        }
                        line++;
                    }
                    part.local_matrix = make_local_matrix_func();

                    parts_.push(part);
            }
            if(lines[line].indexOf("Stats") != -1)
            {
                while(lines[line].indexOf("{") == -1)
                {
                    line++;
                }

                var num;

                while(lines[line].indexOf("}") == -1)
                {
                    if(lines[line].indexOf("gears") != -1)
                    {
                        num = lines[line].match(/[\/.\w]+/g);
                        
                        stats_.num_gears = parseInt(num[1], 10);
                    }else
                    if(lines[line].indexOf("acceleration") != -1)
                    {
                        num = lines[line].match(/[\/.\-\w]+/g);
                        stats_.acceleration = parseFloat(num[1]);
                    }else
                    if(lines[line].indexOf("friction") != -1)
                    {
                        num = lines[line].match(/[\/.\-\w]+/g);
                        stats_.frict1 = parseFloat(num[1]);
                        stats_.frict2 = parseFloat(num[2]);
                    }else
                    if(lines[line].indexOf("switch_zone") != -1)
                    {
                        num = lines[line].match(/[\/.\-\w]+/g);
                        stats_.switch_zone_begin = parseFloat(num[1]);
                        stats_.switch_zone_center = parseFloat(num[2]);
                        stats_.switch_zone_end = parseFloat(num[3]);
                    }else
                    if(lines[line].indexOf("speed_penalty") != -1)
                    {
                        num = lines[line].match(/[\/.\-\w]+/g);
                        stats_.speed_penalty = parseFloat(num[1]);
                    }


                    line++;
                }

            }
            
            line++;
        }


        lines = null;

        var aux_matrix_ = mat4.create(),
        
            final_matrix_ = mat4.create(),
            sun_matrix_ = mat4.create(),
            local_matrix_ = mat4.create(),
        
            position_ = [0.0, 0.0, 0.0],
            velocity_ = [0.0, 0.0, 0.0],
            acceleration_ = [0.0, 0.0, 0.0],

            slope_ = [0.0, 0.0, 0.0];

        mat4.identity(local_matrix_);

        stats_.velocity_before_incr = [0.0, 0.0, 0.0];
        
        /**** stats ****/

        stats_.gears = [];

        var current_gear_ = 0;

        for (i = 0; i < stats_.num_gears; i++) {
            var gear = [];
            gear.acceleration = stats_.acceleration / (stats_.num_gears - i);

            var a = stats_.frict1;
            var b = stats_.frict2;
            var c = -gear.acceleration;

            gear.max_velocity = (-b + Math.sqrt(b*b -4*a*c))/(2*a);
            stats_.gears.push(gear);
        }

        
        
        /**** /stats ****/
        
        this.local_matrix = function(){
            return local_matrix_;
        };
        
        this.position = function(){
            return position_;
        };
        
        this.velocity = function(){
            return velocity_;
        };
            
        this.velocity_scalar = function(){
            var val = Math.sqrt( velocity_[0] * velocity_[0] + velocity_[1] * velocity_[1] + velocity_[2] * velocity_[2] );
            if(val > 0.000001)
            {
                return val;
            } else
            {
                return 0.0;
            }
        };
                
        this.acceleration = function(){
            return acceleration_;
        };
                        
        this.acceleration_scalar = function(){
            var val = Math.sqrt( acceleration_[0] * acceleration_[0] + acceleration_[1] * acceleration_[1] + acceleration_[2] * acceleration_[2] );
            if(val > 0.000001)
            {
                return val;
            } else
            {
                return 0.0;
            }
        };

        this.stats = function(){
            return stats_;
        };

        this.current_gear = function(){
            return current_gear_;
        };
    
        this.set_acceleration = function(acceleration){
            acceleration_[0] = acceleration[0];
            acceleration_[1] = acceleration[1];
            acceleration_[2] = acceleration[2];
        };

        this.Accelerate = function(forward){
            if(forward)
            {
                acceleration_[2] = stats_.gears[current_gear_].acceleration;
            }else{
                current_gear_ = 0;
                stats_.velocity_before_incr[2] = 0.0;
                acceleration_[2] = -stats_.gears[current_gear_].acceleration;
            }
        };

        this.IncrementGear = function(){
            
            if(current_gear_ == stats_.num_gears - 1)
            {
                return;
            }

            var t = (velocity_[2] - stats_.velocity_before_incr[2])/(stats_.gears[current_gear_].max_velocity - stats_.velocity_before_incr[2]);
            
            stats_.t = t;

            var speed_penalty = 0.0;
            if(t > stats_.switch_zone_center)
            {
                speed_penalty = stats_.speed_penalty * (t - stats_.switch_zone_center) / (stats_.switch_zone_end - stats_.switch_zone_center);
            }else
            {
                speed_penalty = stats_.speed_penalty * (-t + stats_.switch_zone_center) / (stats_.switch_zone_center - stats_.switch_zone_begin);
            }

            //if(speed_penalty < 0)speed_penalty = stats_.speed_penalty;
            //alert(speed_penalty);
            velocity_[2] -= speed_penalty;

            if(velocity_[2] < 0)
            {
                velocity_[2] = 0;
            }

            current_gear_++;

            acceleration_[2] = stats_.gears[current_gear_].acceleration;

            stats_.velocity_before_incr[2] = velocity_[2];
        };

        this.Update = function(delta_time){
            
            var v = velocity_[2];
            var k1dx = v;
            var k1dv = acceleration_[2]-Math.abs(v) * v * stats_.frict1- v * stats_.frict2;
            
            v = velocity_[2] + k1dv * delta_time * 0.5;
            var k2dx = v;
            var k2dv = acceleration_[2]-Math.abs(v) * v * stats_.frict1- v * stats_.frict2;
                    
            
            v = velocity_[2] + k2dv * delta_time * 0.5;
            var k3dx = v;
            var k3dv = acceleration_[2]-Math.abs(v) * v * stats_.frict1- v * stats_.frict2;
            
            
            v = velocity_[2] + k3dv * delta_time;
            var k4dx = v;
            var k4dv = acceleration_[2]-Math.abs(v) * v * stats_.frict1- v * stats_.frict2;
            
            var dxdt = (1.0 / 6.0) * (k1dx + 2.0*(k2dx + k3dx) + k4dx);
            var dvdt = (1.0 / 6.0) * (k1dv + 2.0*(k2dv + k3dv) + k4dv);
            
            var incrZ = dxdt * delta_time;
            
            position_[2] += incrZ;
            velocity_[2] += dvdt * delta_time;

            stats_.t = (velocity_[2] - stats_.velocity_before_incr[2])/(stats_.gears[current_gear_].max_velocity - stats_.velocity_before_incr[2]);

            mat4.identity(local_matrix_);
            
            local_matrix_[14] = position_[2];
                
            if(Math.abs( acceleration_[2] ) < 0.00001)
            {
                slope_[0] = slope_[0] - (slope_[0] - dvdt * delta_time*2)*0.005;
            } else
            {
                slope_[0] = slope_[0] - (slope_[0] - dvdt * delta_time*2)*0.005;
            }
                
            mat4.rotateX(local_matrix_, -slope_[0]);
            
            var drift_fac;
            
            drift_fac = 1.0;//1.0 + ( max_velocity_sqr_ - vel_sqr) / max_velocity_sqr_;
            //drift_fac *= drift_fac; drift_fac *= drift_fac;
            
            if(acceleration_[2] === 0)
            {
                drift_fac = 1.0;
            }
            
            
            for(var i = 0; i < wheel_indices_.length; i++)
            {
                if(parts_[wheel_indices_[i]].reverse_rotation)
                {
                    mat4.rotateX(parts_[wheel_indices_[i]].local_matrix_, drift_fac*-incrZ / parts_[wheel_indices_[i]].radius);
                }else
                {
                    mat4.rotateX(parts_[wheel_indices_[i]].local_matrix_, drift_fac*incrZ / parts_[wheel_indices_[i]].radius);
                }
            }
        };
    
        this.Update1 = function(delta_time){
        
            var vel;
        
            velocity_[0] += acceleration_[0] * delta_time;
            velocity_[1] += acceleration_[1] * delta_time;
            velocity_[2] += acceleration_[2] * delta_time;
            
            if(Math.abs(acceleration_[2]) < 0.00001)
            {
                vel = Math.sqrt(velocity_[0] * velocity_[0] + velocity_[1] * velocity_[1] + velocity_[2] * velocity_[2]);
                velocity_[0] += ( - vel * velocity_[0]*0.0001 - velocity_[0]*0.0001) * delta_time;
                velocity_[1] += ( - vel * velocity_[1]*0.0001 - velocity_[1]*0.0001) * delta_time;
                velocity_[2] += ( - vel * velocity_[2]*0.0001 - velocity_[2]*0.0001) * delta_time;
            }
    
            vel = Math.sqrt(velocity_[0] * velocity_[0] + velocity_[1] * velocity_[1] + velocity_[2] * velocity_[2]);
            
            
            if( vel > max_velocity_ )
            {

                var inv_mult = max_velocity_ /  vel ;
                        
                velocity_[0] *= inv_mult;
                velocity_[1] *= inv_mult;
                velocity_[2] *= inv_mult;
                        
                acceleration_[0] = 0;
                acceleration_[1] = 0;
                acceleration_[2] = 0;
            }
                    
            var inccrX  = velocity_[0] * delta_time;
            var inccrY  = velocity_[1] * delta_time;
            var inccrZ  = velocity_[2] * delta_time;
                
            position_[0] += inccrX;
            position_[1] += inccrY;
            position_[2] += inccrZ;
                
            mat4.identity(local_matrix_);
                
            local_matrix_[12] = position_[0];
            local_matrix_[13] = position_[1];
            local_matrix_[14] = position_[2];
            
            
            if(Math.abs( acceleration_[2] ) < 0.00001)
            {
                slope_[0] = slope_[0] - (slope_[0] - acceleration_[2] * 100)*0.05;
            } else
            {
                slope_[0] = slope_[0] - (slope_[0] - acceleration_[2] * 100)*0.0125;
            }
            
            mat4.rotateX(local_matrix_, -slope_[0]);
            
            var drift_fac;
            
            drift_fac = 1.0 + ( max_velocity_sqr_ - vel_sqr) / max_velocity_sqr_;
            //drift_fac *= drift_fac; drift_fac *= drift_fac;
            
            if(acceleration_[2] === 0)
            {
                drift_fac = 1.0;
            }
            
            
            for(var i = 0; i < wheel_indices_.length; i++)
            {
                if(parts_[wheel_indices_[i]].reverse_rotation)
                {
                    mat4.rotateX(parts_[wheel_indices_[i]].local_matrix_, drift_fac*-inccrZ / parts_[wheel_indices_[i]].radius);
                } else
                {
                    mat4.rotateX(parts_[wheel_indices_[i]].local_matrix_, drift_fac*inccrZ / parts_[wheel_indices_[i]].radius);
                }
            }
        };
    
        this.Draw = function(){
            
            if(g_render_state.current_pass == REFLECTION_PASS)
            {
                return;
            }
            
            for(var i = 0; i < parts_.length; i++)
            {
                var matrix = mat4.create();
                var matrix1 = mat4.create();
                
                matrix1 = parts_[i].local_matrix(parts_);
                            
                mat4.multiply(local_matrix_, matrix1, matrix);
                                                        
                if(parts_[i].is_wheel)
                {
                    if(parts_[i].snaptoground)
                    {
                        matrix[13] = parts_[i].offset[1];
                    }
                }else
                    if(parts_[i].parent_index != -1)
                    {
                        if(parts_[parts_[i].parent_index].is_wheel)
                        {
                            if(parts_[parts_[i].parent_index].snaptoground)
                            {
                                matrix[13] = parts_[i].offset[1] + parts_[parts_[i].parent_index].offset[1];
                            }
                        }
                    }
                                        
                if(g_render_state.current_program.hasOwnProperty("uMMatrix"))
                {
                    gl.uniformMatrix4fv(g_render_state.current_program.uMMatrix, false, matrix);
                }
                            
                mat4.multiply(g_render_state.current_cam.view_matrix(), matrix, aux_matrix_);
                if(g_render_state.current_program.hasOwnProperty("uMVMatrix"))
                {
                    gl.uniformMatrix4fv(g_render_state.current_program.uMVMatrix, false, aux_matrix_);
                }
                        
                mat4.multiply(g_render_state.current_cam.projection_matrix(), aux_matrix_, final_matrix_);
                gl.uniformMatrix4fv(g_render_state.current_program.uMVPMatrix, false, final_matrix_);
                
                if(g_render_state.current_program.hasOwnProperty("uSunPMatrix"))
                {
                    mat4.multiply(g_renderer.global_shadow_cam().view_matrix(), matrix, aux_matrix_);
                    mat4.multiply(g_renderer.global_shadow_cam().projection_matrix(), aux_matrix_, sun_matrix_);
                    gl.uniformMatrix4fv(g_render_state.current_program.uSunPMatrix, false, sun_matrix_);
                }
                
                g_materials[parts_[i].material_name].Use();
                parts_[i].mesh.Draw();
            }
        
        };
    
    }
    
    return Car;
})();

var FullScreenQuad = (function() {
    "use strict";
    function FullScreenQuad() {
    
        var positions_,
            tex_coords_,
        
            positions_buffer_,
            tex_coords_buffer_;
        
        positions_ = new Float32Array(18);
        tex_coords_ = new Float32Array(12);
        
        positions_[0] = -1.0; positions_[1] = -1.0; positions_[2] = 0.0;
        positions_[3] = 1.0; positions_[4] = -1.0; positions_[5] = 0.0;
        positions_[6] = -1.0; positions_[7] = 1.0; positions_[8] = 0.0;
        positions_[9] = -1.0; positions_[10] = 1.0; positions_[11] = 0.0;
        positions_[12] = 1.0; positions_[13] = -1.0; positions_[14] = 0.0;
        positions_[15] = 1.0; positions_[16] = 1.0; positions_[17] = 0.0;
        
        tex_coords_[0] = 0.0; tex_coords_[1] = 0.0;
        tex_coords_[2] = 1.0; tex_coords_[3] = 0.0;
        tex_coords_[4] = 0.0; tex_coords_[5] = 1.0;
        tex_coords_[6] = 0.0; tex_coords_[7] = 1.0;
        tex_coords_[8] = 1.0; tex_coords_[9] = 0.0;
        tex_coords_[10] = 1.0; tex_coords_[11] = 1.0;
        
        positions_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positions_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
        positions_buffer_.itemSize = 3;
        positions_buffer_.numItems = 18 / 3;
        
        tex_coords_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, tex_coords_, gl.STATIC_DRAW);
        tex_coords_buffer_.itemSize = 2;
        tex_coords_buffer_.numItems = 12 / 2;
        
        this.Draw = function(){
            
            gl.bindBuffer(gl.ARRAY_BUFFER, positions_buffer_);
            
            gl.enableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
            
            
            gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);

            gl.enableVertexAttribArray(g_render_state.current_program.aVertexUVs);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexUVs, 2, gl.FLOAT, true, 0, 0);
            
            gl.drawArrays(gl.TRIANGLES, 0, positions_buffer_.numItems);
            
            gl.disableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.disableVertexAttribArray(g_render_state.current_program.aVertexUVs);
            
        };
    
    }
    
    return FullScreenQuad;

})();

var paddings2 = [
        4,  4,  5,  9,  8,  12, 10, 3,  4,  4,  6,  10, 3,  6,  3,  5,
        8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  3,  3,  10, 10, 10, 6,
        14, 9,  8,  9,  10, 8,  7,  10, 10, 3,  5,  8,  7,  12, 11, 11,
        8,  11, 8,  7,  8,  10, 9,  13, 8,  8,  9,  4,  5,  4,  10, 6,
        4,  7,  8,  7,  8,  8,  4,  8,  8,  3,  3,  7,  3,  12, 8,  8,
        8,  8,  5,  6,  4,  8,  7,  10, 6,  7,  7,  4,  3,  4,  10, 10,
        10, 7,  3,  5,  5,  10, 6,  6,  8,  18, 15, 5,  15, 8,  10, 10,
        8,  3,  3,  5,  5,  6,  8,  15, 10, 12, 12, 5,  12, 7,  8,  8,
        4,  8,  7,  5,  8,  7,  3,  7,  8,  13, 9,  7,  10, 6,  13, 3,
        6,  10, 3,  3,  5,  8,  7,  3,  8,  17, 7,  7,  3,  7,  6,  3,
        9,  8,  8,  7,  10, 8,  12, 8,  11, 11, 8,  10, 12, 10, 11, 10,
        8,  9,  8,  8,  11, 8,  11, 9,  13, 13, 10, 11, 8,  9,  15, 8,
        7,  8,  7,  5,  8,  8,  10, 7,  8,  8,  7,  8,  10, 8,  8,  8,
        8,  7,  6,  7,  10, 6,  8,  8,  11, 12, 8,  10, 7,  7,  12, 7,
];
//v16,s512
var paddings = [
        15, 16, 18, 33, 28, 43, 38, 12, 16, 16, 22, 36, 12, 22, 12, 20,
        28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 12, 12, 36, 36, 36, 24,
        52, 35, 30, 34, 37, 28, 26, 37, 37, 12, 18, 29, 35, 46, 39, 42,
        30, 41, 31, 27, 28, 36, 33, 49, 31, 30, 31, 16, 20, 16, 36, 23,
        14, 27, 31, 24, 31, 28, 15, 31, 29, 11, 11, 24, 11, 45, 29, 31,
        31, 31, 18, 21, 16, 29, 25, 37, 23, 25, 26, 16, 12, 16, 36, 36,
        38, 24, 12, 19, 18, 37, 20, 20, 28, 64, 54, 17, 55, 29, 38, 37,
        31, 12, 12, 18, 18, 22, 28, 55, 36, 43, 43, 17, 45, 24, 30, 30,
        15, 29, 29, 18, 31, 25, 12, 25, 28, 48, 31, 26, 36, 22, 48, 12,
        21, 36, 12, 11, 20, 30, 26, 12, 28, 62, 25, 26, 11, 27, 21, 11,
        35, 30, 30, 24, 36, 28, 45, 30, 39, 39, 29, 36, 45, 37, 42, 37,
        30, 34, 28, 29, 39, 31, 39, 34, 48, 49, 38, 41, 30, 34, 53, 31,
        27, 30, 26, 19, 29, 28, 37, 25, 30, 30, 24, 28, 35, 30, 31, 30,
        31, 24, 20, 25, 35, 23, 31, 29, 41, 42, 30, 36, 25, 25, 43, 27,
];
var FONT_TEX_SIZE = 1024;
var FONT_HEIGHT = 64;

var TypeMesh = (function(){
    "use strict";
    function TypeMesh(text, start_x, start_y, scale, parent){
    
        var positions_,
            tex_coords_,

            scale_ = scale,
        
            triangle_pos_buffer_,
            tex_coords_buffer_,
        
            num_pos_,
            num_tris_,
        
            num_chars_,
        
            parent_ = parent;
        
        if( parent !== null )
        {
            var par_dims = parent.abs_dims();
            
            start_x *= (par_dims[2] - par_dims[0])/2;
            start_y *= (par_dims[3] - par_dims[1])/2;
            
            start_x += par_dims[0] + (par_dims[2] - par_dims[0])/2 + W_CORNER_PAD;
            start_y += par_dims[1] + (par_dims[3] - par_dims[1])/2 + W_CORNER_PAD;
            
        }
        
        
        num_chars_ = text.length;
        
        positions_ =  new Float32Array(num_chars_*4*3);
        tex_coords_ = new Float32Array(num_chars_*4*2);
        
        num_pos_ = num_chars_*4*3;
        num_tris_ = num_chars_*4;

        var start_x_ = start_x;
        var start_y_ = start_y;
        
        var pad = 0.0;
        var b_ready = false;
        var is_moving_ = false;
        
        for(var i = 0; i < num_chars_; i++)
        {
            
            var char_code = text.charCodeAt(i);
            
            if(char_code >= 1040)
            {
                char_code -= 975;
            }
            
            var shell_y = Math.floor( (char_code - 32) / 16 );
            var shell_x = Math.floor( (char_code - 32) % 16 );
            

            positions_[i*4*3 + 0] = start_x + pad * scale;
            positions_[i*4*3 + 1] = start_y + (64.0*scale)/FONT_TEX_SIZE;
            positions_[i*4*3 + 2] = 0;

            tex_coords_[i*4*2 + 0] = ( shell_x ) / 16;
            tex_coords_[i*4*2 + 1] = ( shell_y ) / 16;
            
            positions_[i*4*3 + 3] = positions_[i*4*3 + 0];
            positions_[i*4*3 + 4] = start_y;
            positions_[i*4*3 + 5] = 0;

            tex_coords_[i*4*2 + 2] = ( shell_x ) / 16;
            tex_coords_[i*4*2 + 3] = ( shell_y ) / 16 + 1.0/16.0;

            pad += paddings[char_code - 32] * global_device_aspect / FONT_TEX_SIZE;

            positions_[i*4*3 + 6] = start_x + pad * scale;
            positions_[i*4*3 + 7] = start_y + (64.0*scale)/FONT_TEX_SIZE;
            positions_[i*4*3 + 8] = 0;

            tex_coords_[i*4*2 + 4] = ( shell_x ) / 16 + paddings[char_code - 32] / FONT_TEX_SIZE;
            tex_coords_[i*4*2 + 5] = ( shell_y ) / 16;
            
            positions_[i*4*3 + 9] = positions_[i*4*3 + 6];
            positions_[i*4*3 + 10] = start_y;
            positions_[i*4*3 + 11] = 0;

            tex_coords_[i*4*2 + 6] = ( shell_x ) / 16 + paddings[char_code - 32] / FONT_TEX_SIZE;
            tex_coords_[i*4*2 + 7] = ( shell_y ) / 16 + 1.0/16.0;

        }

        triangle_pos_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
        triangle_pos_buffer_.itemSize = 3;
        triangle_pos_buffer_.numItems = num_pos_/3;
        
        tex_coords_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, tex_coords_, gl.STATIC_DRAW);
        tex_coords_buffer_.itemSize = 2;
        tex_coords_buffer_.numItems = num_pos_/3;
        
        num_tris_ = num_chars_ * 4;

        b_ready = true;

        this.ChangeText = function(text){

            if(is_moving_)
            {
                return;
            }
            
            b_ready = false;

            num_chars_ = text.length;

            var new_positions_ =  new Float32Array(num_chars_*4*3);
            var new_tex_coords_ = new Float32Array(num_chars_*4*2);

            var pad = 0.0;

            for(var i = 0; i < num_chars_; i++)
            {
            
            var char_code = text.charCodeAt(i);
            
            if(char_code >= 1040)
            {
                char_code -= 975;
            }
            var shell_y = Math.floor( (char_code - 32) / 16 );
            var shell_x = Math.floor( (char_code - 32) % 16 );
            

            new_positions_[i*4*3 + 0] = start_x_ + pad * scale_;
            new_positions_[i*4*3 + 1] = start_y_ + (64.0*scale_)/FONT_TEX_SIZE;
            new_positions_[i*4*3 + 2] = 0;

            new_tex_coords_[i*4*2 + 0] = ( shell_x ) / 16;
            new_tex_coords_[i*4*2 + 1] = ( shell_y ) / 16;
            
            new_positions_[i*4*3 + 3] = new_positions_[i*4*3 + 0];
            new_positions_[i*4*3 + 4] = start_y_;
            new_positions_[i*4*3 + 5] = 0;

            new_tex_coords_[i*4*2 + 2] = ( shell_x ) / 16;
            new_tex_coords_[i*4*2 + 3] = ( shell_y ) / 16 + 1.0/16.0;

            pad += paddings[char_code - 32] * global_device_aspect / FONT_TEX_SIZE;

            new_positions_[i*4*3 + 6] = start_x_ + pad * scale_;
            new_positions_[i*4*3 + 7] = start_y_ + (64.0*scale_)/FONT_TEX_SIZE;
            new_positions_[i*4*3 + 8] = 0;

            new_tex_coords_[i*4*2 + 4] = ( shell_x ) / 16 + paddings[char_code - 32] / FONT_TEX_SIZE;
            new_tex_coords_[i*4*2 + 5] = ( shell_y ) / 16;
            
            new_positions_[i*4*3 + 9] = new_positions_[i*4*3 + 6];
            new_positions_[i*4*3 + 10] = start_y_;
            new_positions_[i*4*3 + 11] = 0;

            new_tex_coords_[i*4*2 + 6] = ( shell_x ) / 16 + paddings[char_code - 32] / FONT_TEX_SIZE;
            new_tex_coords_[i*4*2 + 7] = ( shell_y ) / 16 + 1.0/16.0;

            }

            var new_num_pos_ = num_chars_*4*3;
            var new_num_tris_ = num_chars_*4;

            var new_triangle_pos_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, new_triangle_pos_buffer_);
            gl.bufferData(gl.ARRAY_BUFFER, new_positions_, gl.STATIC_DRAW);
            new_triangle_pos_buffer_.itemSize = 3;
            new_triangle_pos_buffer_.numItems = new_num_pos_/3;
        
            var new_tex_coords_buffer_ = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, new_tex_coords_buffer_);
            gl.bufferData(gl.ARRAY_BUFFER, new_tex_coords_, gl.STATIC_DRAW);
            new_tex_coords_buffer_.itemSize = 2;
            new_tex_coords_buffer_.numItems = new_num_pos_/3;

            triangle_pos_buffer_ = new_triangle_pos_buffer_;
            tex_coords_buffer_ = new_tex_coords_buffer_;

            num_pos_ = new_num_pos_;
            num_tris_ = new_num_tris_;

            positions_ = new_positions_;
            tex_coords_ = new_tex_coords_;

            b_ready = true;

        };
                
        this.Move = function(dx, dy){
        
            //is_moving_ = true;

            for(var i = 0; i < num_tris_; i++)
            {
                positions_[i * 3 + 0] += dx;
                positions_[i * 3 + 1] += dy;
            }

            start_x_ += dx;
            start_y_ += dy;
            
            if(b_ready)
            {
                var new_triangle_pos_buffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, new_triangle_pos_buffer);
                gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
                new_triangle_pos_buffer.itemSize = 3;
                new_triangle_pos_buffer.numItems = num_pos_/3;
            
                triangle_pos_buffer_ = new_triangle_pos_buffer;
            }

            //is_moving_ = false;
            
        };
        
        this.Draw = function(){

            if(g_render_state.current_pass != UI_DRAW_PASS)
            {
                return;
            }
            g_renderer.BindTexture(DIFFUSEMAP_SLOT, font_texture);
                                    
            gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
            
            gl.enableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);

                gl.enableVertexAttribArray(g_render_state.current_program.aVertexUVs);
                gl.vertexAttribPointer(g_render_state.current_program.aVertexUVs, 2, gl.FLOAT, true, 0, 0);
                
            }
                    
            
            gl.drawArrays (gl.TRIANGLE_STRIP, 0, num_tris_);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.disableVertexAttribArray(g_render_state.current_program.aVertexUVs);
            }
                
            gl.disableVertexAttribArray(g_render_state.current_program.aVertexPosition);


        };
        
    
    }
    
    return TypeMesh;

})();

var W_CORNER_PAD = 0.01;

var WF_COORDS = [[0.04, 0.04, 0.04, 0.45, 0.46, 0.04, 0.46, 0.45],
                [0.58, 0.04, 0.58, 0.46, 0.96, 0.04, 0.96, 0.46]];

var WinFrame = (function(){
    "use strict";
    function WinFrame(start_x, start_y, width, height, skin, parent, mode){
    
        var positions_;
        var tex_coords_;
        
        var triangle_pos_buffer_;
        var tex_coords_buffer_;
        
        var num_pos_ = 84;
        var num_tris_ = num_pos_/3;
        
        
        positions_ =  new Float32Array(num_tris_*3);
        tex_coords_ = new Float32Array(num_tris_*2);
        
        var parent_ = parent;
        
        
        if(parent !== null)
        {
            var par_dims = parent.abs_dims();
                        
                        
            if(mode == 1)
            {
                width   *= (par_dims[2] - par_dims[0])/2 - W_CORNER_PAD*0;
                height  *= (par_dims[3] - par_dims[1])/2 - W_CORNER_PAD*0;
                                        
                start_x *= (par_dims[2] - par_dims[0])/2;
                start_y *= (par_dims[3] - par_dims[1])/2;
                
                start_x += par_dims[0] + (par_dims[2] - par_dims[0])/2 + W_CORNER_PAD*0;
                start_y += par_dims[1] + (par_dims[3] - par_dims[1])/2 + W_CORNER_PAD*0;
            }
            

        }
        
        var dims_ = [start_x, start_y, start_x + width, start_y + height];
        
                
        width -= 2 * W_CORNER_PAD;
        height -= 2 * W_CORNER_PAD/ global_device_aspect;
        
        positions_[0] = start_x;                            positions_[1] = start_y + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[0] = WF_COORDS[skin][2];                tex_coords_[1] = WF_COORDS[skin][3];
        
        positions_[3] = start_x;                            positions_[4] = start_y;
        tex_coords_[2] = WF_COORDS[skin][0];                tex_coords_[3] = WF_COORDS[skin][1];
                
        positions_[6] = start_x + W_CORNER_PAD;             positions_[7] = start_y + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[4] = WF_COORDS[skin][6];                tex_coords_[5] = WF_COORDS[skin][7];
                        
        positions_[9] = start_x + W_CORNER_PAD;             positions_[10] = start_y;
        tex_coords_[6] = WF_COORDS[skin][4];                tex_coords_[7] = WF_COORDS[skin][5];
                                
        positions_[12] = start_x + W_CORNER_PAD + width;    positions_[13] = start_y + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[8] = WF_COORDS[skin][6];                tex_coords_[9] = WF_COORDS[skin][7];
                                        
        positions_[15] = start_x + W_CORNER_PAD + width;    positions_[16] = start_y;
        tex_coords_[10] = WF_COORDS[skin][4];               tex_coords_[11] = WF_COORDS[skin][5];
                                        
        positions_[18] = start_x + 2*W_CORNER_PAD + width;  positions_[19] = start_y + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[12] = WF_COORDS[skin][2];               tex_coords_[13] = WF_COORDS[skin][3];
                                                
        positions_[21] = start_x + 2*W_CORNER_PAD + width;  positions_[22] = start_y;
        tex_coords_[14] = WF_COORDS[skin][0];               tex_coords_[15] = WF_COORDS[skin][1];
                                        
        positions_[24] = positions_[21];                    positions_[25] = positions_[22];
        tex_coords_[16] = tex_coords_[14];                  tex_coords_[17] = tex_coords_[15];
        //              
        positions_[27] = positions_[0];                     positions_[28] = positions_[1] + height;
        tex_coords_[18] = tex_coords_[0];                   tex_coords_[19] = tex_coords_[1];
                                                                
        positions_[30] = positions_[0];                     positions_[31] = positions_[1] + height;
        tex_coords_[20] = tex_coords_[0];                   tex_coords_[21] = tex_coords_[1];
                                                                        
        positions_[33] = positions_[0];                     positions_[34] = positions_[1];
        tex_coords_[22] = tex_coords_[0];                   tex_coords_[23] = tex_coords_[1];
                                                                                
        positions_[36] = positions_[6];                     positions_[37] = positions_[7] + height;
        tex_coords_[24] = tex_coords_[4];                   tex_coords_[25] = tex_coords_[5];
                                                                                        
        positions_[39] = positions_[6];                     positions_[40] = positions_[7];
        tex_coords_[26] = tex_coords_[4];                   tex_coords_[27] = tex_coords_[5];
                                                                                                
        positions_[42] = positions_[12];                    positions_[43] = positions_[13] + height;
        tex_coords_[28] = tex_coords_[8];                   tex_coords_[29] = tex_coords_[9];
                                                                                                        
        positions_[45] = positions_[12];                    positions_[46] = positions_[13];
        tex_coords_[30] = tex_coords_[8];                   tex_coords_[31] = tex_coords_[9];
                                                                                                                
        positions_[48] = positions_[18];                    positions_[49] = positions_[19] + height;
        tex_coords_[32] = tex_coords_[12];                  tex_coords_[33] = tex_coords_[13];
                                                                                                                        
        positions_[51] = positions_[18];                    positions_[52] = positions_[19];
        tex_coords_[34] = tex_coords_[12];                  tex_coords_[35] = tex_coords_[13];
                                                                                                                                
        positions_[54] = positions_[18];                    positions_[55] = positions_[19];
        tex_coords_[36] = tex_coords_[12];                  tex_coords_[37] = tex_coords_[13];
        //                                                                                                                          
        positions_[57] = positions_[27];                    positions_[58] = positions_[28] + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[38] = tex_coords_[2];                   tex_coords_[39] = tex_coords_[3];
                                                                                                                                    
        positions_[60] = positions_[27];                    positions_[61] = positions_[28] + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[40] = tex_coords_[2];                   tex_coords_[41] = tex_coords_[3];
            
        positions_[63] = positions_[27];                    positions_[64] = positions_[28];
        tex_coords_[42] = tex_coords_[18];                  tex_coords_[43] = tex_coords_[19];
                                                                                            
        positions_[66] = positions_[36];                    positions_[67] = positions_[37] + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[44] = tex_coords_[6];                   tex_coords_[45] = tex_coords_[7];
                                                                                                    
        positions_[69] = positions_[36];                    positions_[70] = positions_[37];
        tex_coords_[46] = tex_coords_[24];                  tex_coords_[47] = tex_coords_[25];
                                                                                                            
        positions_[72] = positions_[36] + width;            positions_[73] = positions_[37] + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[48] = tex_coords_[10];                  tex_coords_[49] = tex_coords_[11];
                                                                                                                    
        positions_[75] = positions_[36] + width;            positions_[76] = positions_[37];
        tex_coords_[50] = tex_coords_[8];                   tex_coords_[51] = tex_coords_[9];
                                                                                                                            
        positions_[78] = positions_[48];                    positions_[79] = positions_[49] + W_CORNER_PAD/ global_device_aspect;
        tex_coords_[52] = tex_coords_[14];                  tex_coords_[53] = tex_coords_[15];
                                                                                
        positions_[81] = positions_[48];                    positions_[82] = positions_[49];
        tex_coords_[54] = tex_coords_[12];                  tex_coords_[55] = tex_coords_[13];
        
        
        //if(parent == null)
        for(var i = 0; i < num_tris_; i++)
        {
            //positions_[i * 3 + 1] /= global_device_aspect;
            positions_[i * 3 + 2] = 0;
        }
        
        
        /************************************************/
        
        triangle_pos_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
        triangle_pos_buffer_.itemSize = 3;
        triangle_pos_buffer_.numItems = num_pos_/3;
        
        tex_coords_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, tex_coords_, gl.STATIC_DRAW);
        tex_coords_buffer_.itemSize = 2;
        tex_coords_buffer_.numItems = num_pos_/3;
            
        this.dims = function(){
            return dims_;
        };
        
        this.abs_dims = function(){
            if(parent_ === null)
            {
                return dims_;
            }
            
            var par_dims = parent_.abs_dims();
            for(var i = 0; i < 4; i+=2)
            {
                par_dims[i] += dims_[i];
                par_dims[i] *= (par_dims[2] - par_dims[0]);
                par_dims[i + 1] += dims_[i + 1] * (par_dims[3] - par_dims[1]);
                par_dims[i + 1] *= (par_dims[3] - par_dims[1]);
            }
            return par_dims;
        };
        
        this.set_parent = function(parent){
            parent_ = parent;
        };
        
        this.Move = function(dx, dy){
        
            for(var i = 0; i < num_tris_; i++)
            {
                positions_[i * 3 + 0] += dx;
                positions_[i * 3 + 1] += dy;
            }
            
            dims_[0] += dx; dims_[2] += dx;
            dims_[1] += dy; dims_[3] += dy;
                    
            var new_triangle_pos_buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, new_triangle_pos_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
            new_triangle_pos_buffer.itemSize = 3;
            new_triangle_pos_buffer.numItems = num_pos_/3;
            
            triangle_pos_buffer_ = new_triangle_pos_buffer;
            
        };
        
        this.Draw = function(){

            if(g_render_state.current_pass != UI_DRAW_PASS)
            {
                return;
            }
            g_renderer.BindTexture(DIFFUSEMAP_SLOT, win_texture);
                        
            gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
            
            gl.enableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);

                gl.enableVertexAttribArray(g_render_state.current_program.aVertexUVs);
                gl.vertexAttribPointer(g_render_state.current_program.aVertexUVs, 2, gl.FLOAT, true, 0, 0);
                
            }
                    
            
            gl.drawArrays (gl.TRIANGLE_STRIP, 0, num_tris_);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.disableVertexAttribArray(g_render_state.current_program.aVertexUVs);
            }
                
            gl.disableVertexAttribArray(g_render_state.current_program.aVertexPosition);


        };
    
    }

    return WinFrame;
})();

var WinIcon = (function(){
    "use strict";
    function WinIcon(dims, coords, mode){
        var positions_,
            tex_coords_,
        
            triangle_pos_buffer_,
            tex_coords_buffer_,
        
            num_pos_ = 4 * 3,
            num_tris_ = num_pos_/3,
        
            dims_ = dims;
        
        positions_ =  new Float32Array(num_tris_*3);
        tex_coords_ = new Float32Array(num_tris_*2);
        
        positions_[0] = dims[0];        positions_[1] = dims[1] + (dims[3] - dims[1]);
        tex_coords_[0] = coords[0];     tex_coords_[1] = coords[1] + (coords[3] - coords[1]);
        positions_[3] = dims[0];        positions_[4] = dims[1];
        tex_coords_[2] = coords[0];     tex_coords_[3] = coords[1];
        positions_[6] = dims[2];        positions_[7] = dims[3];
        tex_coords_[4] = coords[2];     tex_coords_[5] = coords[3];
        positions_[9] = dims[2];        positions_[10] = dims[3] - (dims[3] - dims[1]);
        tex_coords_[6] = coords[2];     tex_coords_[7] = coords[3] - (coords[3] - coords[1]);
        
        if(mode == 1)
        {
            for(var i = 0; i < num_tris_; i++)
            {
                positions_[i * 3 + 1] /= global_device_aspect;
            }
        
            dims_[1] /= global_device_aspect;
            dims_[3] /= global_device_aspect;
        }

        /***********************************************/
                
        triangle_pos_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
        triangle_pos_buffer_.itemSize = 3;
        triangle_pos_buffer_.numItems = num_pos_/3;
        
        tex_coords_buffer_ = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);
        gl.bufferData(gl.ARRAY_BUFFER, tex_coords_, gl.STATIC_DRAW);
        tex_coords_buffer_.itemSize = 2;
        tex_coords_buffer_.numItems = num_pos_/3;
        
        this.abs_dims = function(){
            return dims_;
        };
                
        this.Move = function(dx, dy){
        
            for(var i = 0; i < num_tris_; i++)
            {
                positions_[i * 3 + 0] += dx;
                positions_[i * 3 + 1] += dy;
            }
            
            dims_[0] += dx; dims_[2] += dx;
            dims_[1] += dy; dims_[3] += dy;
                    
            var new_triangle_pos_buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, new_triangle_pos_buffer);
            gl.bufferData(gl.ARRAY_BUFFER, positions_, gl.STATIC_DRAW);
            new_triangle_pos_buffer.itemSize = 3;
            new_triangle_pos_buffer.numItems = num_pos_/3;
            
            triangle_pos_buffer_ = new_triangle_pos_buffer;
            
        };

        this.Draw = function(){

            if(g_render_state.current_pass != UI_DRAW_PASS)
            {
                return;
            }
            g_renderer.BindTexture(DIFFUSEMAP_SLOT, win_texture);
                        
            gl.bindBuffer(gl.ARRAY_BUFFER, triangle_pos_buffer_);
            
            gl.enableVertexAttribArray(g_render_state.current_program.aVertexPosition);
            gl.vertexAttribPointer(g_render_state.current_program.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.bindBuffer(gl.ARRAY_BUFFER, tex_coords_buffer_);

                gl.enableVertexAttribArray(g_render_state.current_program.aVertexUVs);
                gl.vertexAttribPointer(g_render_state.current_program.aVertexUVs, 2, gl.FLOAT, true, 0, 0);
                
            }
                    
            
            gl.drawArrays (gl.TRIANGLE_STRIP, 0, num_tris_);
            
            if(g_render_state.current_program.aVertexUVs != -1)
            {
                gl.disableVertexAttribArray(g_render_state.current_program.aVertexUVs);
            }
                
            gl.disableVertexAttribArray(g_render_state.current_program.aVertexPosition);


        };
        
    }
    
    return WinIcon;
})();
